//ICS 314 - Sundial Project
//Yosetime Group
//Spring 2013

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import java.awt.print.PageFormat;
import java.awt.print.Printable;
import java.awt.print.PrinterException;

/** The Gnomon class paints a 2D gnomon (side view) with the angle
 *  determined by setting this.latitude
 * 
 * @author Kyle Berney
 */
public class Gnomon extends JPanel implements Printable{
	private double latitude;	//[0, 90] degrees
	private int x = 50;			//x pixel position of line
	private int y = 50;			//y pixel position of line

	/**
	 * Constructor
	 */
	public Gnomon(){
		super();
	}

	/**
	 * Sets this.latitude to the given double lat
	 * 
	 * @param	lat	the desired latitude to be set
	 */
	public void setLatitude(double lat){
		if (lat >= 0. && lat <= 90.){
			this.latitude = lat;
			this.repaint();
		}
	}

	/**
	 * Returns this.latitude
	 * 
	 * @return		this.latitude
	 */
	public double getLatitude(){
		return this.latitude;
	}

	/**
	 * Returns the angle between the bottom line defined by
	 * the Cartesian coordinates (1, 0) and the given (x, y) coordinates in radians
	 * 
	 * @return		the angle between the lines in radians
	 */
	public double angleBetween(int x, int y){
		double innerp = x;
		double mag1 = 1;
		double mag2 = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2));

		if (x >= 0){
			return Math.acos(innerp / (mag1 * mag2));
		}
		else {
			return 2*Math.PI - Math.acos(innerp / (mag1 * mag2));
		}
	}

	/**
	 * Paints the panel with 2D graphics of the gnomon
	 */
	public void paintComponent(Graphics g){
		super.paintComponent(g);
		this.setBackground(Color.WHITE);

		Graphics2D g2 = (Graphics2D)g;
		g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

		g2.setColor(Color.BLACK);
		g2.drawLine(50, 250, 250, 250);
		double error = getPos();
		g2.drawLine(50, 250, this.x, this.y);

		String display = "Latitude = " + this.latitude + " degrees";
		g2.drawString(display, 25, 25);
	}

	/**
	 * Normalizes the vector defined by the pixel position (this.x, this.y)
	 * translated to Cartesian coordinates, then scales it by 200.
	 * Sets this.x and this.y to the new scaled pixel positions.
	 */
	private void scale(){
		double tempx = (double)(this.x - 50);
		double tempy = (double)(250 - this.y);
		double mag = Math.pow(tempx, 2) + Math.pow(tempy, 2);
		mag = Math.sqrt(mag);
		tempx = (tempx / mag) * 200;
		tempy = (tempy / mag) * 200;

		this.x = (int)(tempx + 50);
		this.y = (int)(250 - tempy);
	}

	/**
	 * Sets this.x and this.y to the (x, y) pixel position, such that
	 * the line drawn is close to the desired angle given by this.latitude
	 * 
	 * @return		the error in degrees between the desired angle, this.latitude, and the actual angle displayed
	 */
	protected double getPos(){
		if (this.latitude == 90.){
			this.x = 50;
			this.y = 50;
			return 0.;
		}
		else if (this.latitude == 0.){
			this.x = 250;
			this.y = 250;
			return 0.;
		}

		int tempx = 51;
		int tempy = 51;
		double min = Double.MAX_VALUE;
		while (tempx < 250 && tempy < 250){
			double deg = angleBetween(tempx - 50, 250 - tempy) * (180. / Math.PI);
			double e = Math.abs(this.latitude - deg);
			if (e < min){
				min = e;
				this.x = tempx;
				this.y = tempy;
			}
			tempx++;
			tempy++;
		}
		scale();
		return Math.abs(this.latitude - (angleBetween(this.x - 50, 250 - this.y) * (180. / Math.PI)));
	}

	/**
	 * Prints the conents of the panel
	 */
	public int print(Graphics g, PageFormat p, int pageNum) throws PrinterException {
		if (pageNum > 0)
			return Printable.NO_SUCH_PAGE;

		Graphics2D g2 = (Graphics2D)g;
		g2.translate(p.getImageableX(), p.getImageableY());
		this.paint(g2);
		return Printable.PAGE_EXISTS;
	}
}
